package middleware

import (
	"encoding/json"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/worryry/8-pigeons/pkg/setting"
	"time"
)

type Claims struct {
	AppKey    string `json:"appKey"`
	AppSecret string `json:"appSecret"`
	jwt.StandardClaims
}

type Subject struct {
	UserId   int    `json:"userId"`
	UserName string `json:"userName"`
}

// GenerateToken 根据用户的用户名和密码进行校验，然后将用户基本信息写入body
func GenerateToken(appKey, appSecret, userName string, userId int) (string, error) {
	//校验用户名和密码是否正确，正确之后生成新的ak/sk,拿来做校验生成新的token
	//设置token有效时间
	nowTime := time.Now()
	expireTime := nowTime.Add(setting.GetDuration("jwt.expire") * time.Second)
	sub, err := json.Marshal(Subject{
		UserId:   userId,
		UserName: userName,
	})
	if err != nil {
		return "", err
	}
	claims := Claims{
		AppKey:    appKey,
		AppSecret: appSecret,
		StandardClaims: jwt.StandardClaims{
			// 过期时间
			ExpiresAt: expireTime.Unix(),
			// 指定token发行人
			Issuer:  setting.GetString("jwt.issuer"),
			Subject: string(sub),
		},
	}

	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	//该方法内部生成签名字符串，再用于获取完整、已签名的token
	//fmt.Println("key:", global.JwtSetting.Secret)
	token, err := tokenClaims.SignedString([]byte(setting.GetString("jwt.secret")))
	return token, err
}

// ParseToken 根据传入的token值获取到Claims对象信息，（进而获取其中的用户名和密码）
func ParseToken(token string) (*Claims, error) {
	// 指定加密密钥
	var jwtSecret = []byte(setting.GetString("jwt.secret"))
	//用于解析鉴权的声明，方法内部主要是具体的解码和校验的过程，最终返回*Token
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})

	if tokenClaims != nil {
		// 从tokenClaims中获取到Claims对象，并使用断言，将该对象转换为我们自己定义的Claims
		// 要传入指针，项目中结构体都是用指针传递，节省空间。
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			fmt.Println(claims.AppKey, claims.AppSecret, claims.StandardClaims)
			fmt.Println(fmt.Sprintf("%T,%v", claims, claims))
			return claims, nil
		}
	}
	return nil, err

}
